#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <Utility.h>

#include "FreeRTOS.h"
#include "timers.h"

#include <phApp_Init.h>
#include <phNfcLib_Int.h>
#include <phNfcLib_Initialization.h>
#include "BSP.h"
#include "Reader.h"
#include "log/log2.h"

#include "config/config2.h"
#include <Reader/Reader.h>
#include <Reader/ReaderDesfire2.h>

#include "reader_samav3.h"

extern phalMfdfEVx_SamAV3_NonX_DataParams_t  palMfdfEVx;	/* Pointer to MIFAREDESFire EVx data-params for SAM in S mode */
extern phhalHw_SamAV3_DataParams_t stHal_SamAv3;

/*===================================================================================*/

#define AID_ISSUE		0xCF0001
#define AID_DATA		0xCF0002

#define KEY_NO_KFR0		0x01		//工厂默认读密钥号（卡）
#define KEY_NO_KUR		0x01		//用户读密钥号（卡）
#define	KEY_NO_KMR		0x01		//厂商读密钥号（卡）

#define FID_MANU_INFO		0x00	//厂商信息文件ID
#define FID_USER_INFO		0x00	//用户信息文件ID
#define FID_APPLE_WALLET	0x01	//苹果钱包文件ID
#define FID_GOOGLE_WALLET	0x02	//谷歌钱包文件ID
#define FID_LEAF			0x03	//LEAF卡文件ID
#define FID_KEY_DATA		0x10	//密钥数据文件ID

//密钥初始化版本号
#define KEY_DEFAULT_VERSION		0x00	//初始密钥版本

#define KEY_F_VERSION		0x01	//工厂密钥版本
#define KEY_M_VERSION		0x01	//厂商密钥版本
#define KEY_C_VERSION		0x01	//客户密钥版本
#define KEY_U_VERSION		0x01	//用户密钥版本

//苹果密钥版本
#define KEY_APPLE_PRIV_VERSION	0x01
#define KEY_APPLE_CRED_VERSION	0x01

//谷歌密钥版本
#define KEY_GOOGLE_VERSION		0x01

typedef enum {
	CARD_T_USER = 0,		//用户配置卡
	CARD_T_CUSTOM = 1,		//客户化卡
	CARD_T_MANU = 2,		//厂商配置卡
	CARD_T_INIT = 3,		//初始化卡
}card_type_t;

#pragma pack(1)

//公共文件
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t type;		//类型：0 - 用户配置卡。1 - 授权卡。2 - 厂商配置卡。3 - 激活卡。	
	uint8_t isser_code[16];//厂商信息
	uint8_t cmac[8];
}card_info_t;

//配置卡密钥
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t isser_code[16];//验证码
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}cfg_keys_t;
//密钥数据
typedef struct {
	uint16_t version;	//版本	
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}key_data_t;

#pragma pack()

typedef struct {
	card_info_t info;				//发行信息
	card_info_t user;				//用户信息
	key_data_t key_datas;			//密钥数据
	uint8_t uid[8];
	uint8_t ulen;
}cfg_card_t;

static void reader_pr_cfg_info(const card_info_t* card_info){
	LOG2_DBG("version: %X", card_info->version);
	LOG2_DBG("time: %u", card_info->time);
	LOG2_DBG("type: %u", card_info->type);
	LOG2_BUF_DBG("isser_code", card_info->isser_code, sizeof(card_info->isser_code));
	LOG2_BUF_DBG("cmac", card_info->cmac, sizeof(card_info->cmac));
}

static void reader_pr_cfg_keys(const cfg_keys_t* cfg_keys){
	LOG2_DBG("version: %X", cfg_keys->version);
	LOG2_DBG("time: %u", cfg_keys->time);
	LOG2_BUF_DBG("isser_code", cfg_keys->isser_code, sizeof(cfg_keys->isser_code));
	LOG2_DBG("key_num: %u", cfg_keys->key_num);
	for(int i = 0; i < cfg_keys->key_num; i++){
		LOG2_DBG("key_id: %u", cfg_keys->keys[i].id);
		LOG2_DBG("key_ver: %u", cfg_keys->keys[i].ver);
		LOG2_DBG("key_type: %u", cfg_keys->keys[i].type);
		LOG2_BUF_DBG("key_val", cfg_keys->keys[i].data, sizeof(cfg_keys->keys[i].data));
	}
	LOG2_BUF_DBG("cmac", cfg_keys->cmac, sizeof(cfg_keys->cmac));
}

static void reader_pr_key_data(const key_data_t* key_data){
	LOG2_DBG("version: %X", key_data->version);	
	LOG2_DBG("key_num: %u", key_data->key_num);
	for(int i = 0; i < key_data->key_num; i++){
		LOG2_DBG("key_id: %u", key_data->keys[i].id);
		LOG2_DBG("key_ver: %u", key_data->keys[i].ver);
		LOG2_DBG("key_type: %u", key_data->keys[i].type);
		LOG2_BUF_DBG("key_val", key_data->keys[i].data, sizeof(key_data->keys[i].data));
	}
	LOG2_BUF_DBG("cmac", key_data->cmac, sizeof(key_data->cmac));
}

static void reader_pr_cfg_card(const cfg_card_t* cfg_card){
	reader_pr_cfg_info(&cfg_card->info);
	reader_pr_key_data(&cfg_card->key_datas);
}

static int reader_cfg_select_app(uint32_t aid){
	phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;

    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, (uint8_t*)&aid, NULL);
	if(status){
		LOG2_ERR("select app(%06X) fail: %04X", aid, status);
	}
	return status;
}

static int reader_cfg_auth(uint8_t key_no, uint8_t ver, uint8_t card_key_no){
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	phStatus_t status = phalMfdfEVx_AuthenticateAES(
		pAlMfdfEVx,
		PHAL_MFDFEVX_NO_DIVERSIFICATION,
		key_no,
		ver,
		card_key_no,
		NULL,
		0);
	CHECK_SUCCESS(status);
	return status;
}

static int reader_cfg_auth_div(uint8_t key_no, uint8_t ver, uint8_t card_key_no, uint8_t* div, uint8_t div_len){
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    phStatus_t status = phalMfdfEVx_AuthenticateAES(
		pAlMfdfEVx,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		key_no,
		ver,
		card_key_no,
		div,
		div_len);
	CHECK_SUCCESS(status);
	return status;
}

//生成DIV
static void reader_cfg_gen_div(uint8_t uid[], uint32_t aid, uint8_t div[16]){
	uint8_t buf[16];
	memset(buf, 0, sizeof(buf));
	memcpy(buf, uid, 7);
	buf[8] = aid >> 16;
	buf[9] = aid >> 8;
	buf[10] = aid;
	memcpy(div, buf, 16);
}

//分散密钥
static void reader_cfg_div_key(uint8_t* skey, uint8_t* div, uint8_t dlen, uint8_t * dkey){
	LOG2_BUF_DBG("skey", skey, 16);
	LOG2_BUF_DBG("div", div, dlen);
	void * pDataParams = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_DIVERSIFY);
	phStatus_t status = phCryptoSym_DiversifyDirectKey(
		pDataParams,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		skey,
		PH_KEYSTORE_KEY_TYPE_AES128,
		div,
		dlen,
		dkey
		);
	LOG2_BUF_DBG("dkey", dkey, 16);	
}

//不分散认证
static int reader_cfg_auth_card(uint8_t kid, uint8_t card_key_no){
	//认证密钥
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	int status;
	uint8_t key_ver = KEY_F_VERSION;
	/*AES Authenticate First*/
	status = phalMfdfEVx_AuthenticateAES(
		pAlMfdfEVx,
		PHAL_MFDFEVX_NO_DIVERSIFICATION,
		kid,
		key_ver,
		card_key_no,
		NULL,
		0);
	CHECK_SUCCESS(status);
	return 0;
}
//分散认证
static int reader_cfg_auth_card_div(uint8_t kid, uint8_t kver, uint8_t card_key_no, uint8_t* div, uint8_t dlen){
	//认证密钥
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	int status;	
	/*AES Authenticate First*/
	status = phalMfdfEVx_AuthenticateAES(
		pAlMfdfEVx,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		kid,
		kver,
		card_key_no,
		div,
		dlen);
	CHECK_SUCCESS(status);
	return 0;
}

//分散密钥后，检测mac
static int reader_cfg_check_mac_div(uint8_t kid, uint8_t key_ver, uint8_t div[16], uint8_t* data, uint16_t dlen){
	phStatus_t status;
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
		kid,
		key_ver,
		div,
		16));

	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_VerifyMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		data,
		dlen));
	return 0;
}


static int reader_cfg_read(uint8_t bFileNo, uint16_t off, void *data, uint16_t dlen, uint16_t *rlen){
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	phStatus_t status;
	uint8_t offset[3] = {(uint8_t)off, (uint8_t)(off >> 8), 0x00};
	uint8_t length[3] = {(uint8_t)dlen, (uint8_t)(dlen >> 8), 0x00};
	uint8_t *pdata = NULL;
	uint16_t len = 0;
	uint8_t bOption = PHAL_MFDFEVX_COMMUNICATION_ENC;
	uint8_t* rdata = data;

	*rlen = 0;
	while(1){
		len = 0;
		pdata = NULL;
		status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			bOption,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&offset[0],
			&length[0],
			&pdata,
			&len
			);
		if((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING){
			break;
		}
		memcpy(rdata, pdata, len);
		rdata += len;
		//RXCHAINING下，offset与length参数被忽略
		bOption = PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING;
	}
	
	if(status == PH_ERR_SUCCESS){
		memcpy(rdata, pdata, len);
		*rlen = rdata - (uint8_t*)data + len;
	}
	else{
		LOG2_ERR("phalMfdfEVx_ReadData fail: %04X", status);
	}

	return status;
}

static int reader_cfg_read_data2(uint8_t bFileNo, uint16_t off, void *data, uint16_t dlen){
	uint16_t rlen = 0;
	phStatus_t status = reader_cfg_read(bFileNo, off, data, dlen, &rlen);
	CHECK_SUCCESS(status);
	if(rlen != dlen){
		LOG2_ERR("rxlen=%d, len=%d", rlen, dlen);
		return -1;
	}
	return 0;
}

static int reader_cfg_read_data(uint8_t bFileNo, void *data, uint16_t dlen){
	return reader_cfg_read_data2(bFileNo, 0, data, dlen);
}

//读取密钥数据文件
static int reader_cfg_read_key_data(key_data_t* key_data){
	uint16_t offset = 0;
	//读取版本和密钥数
	int ret = reader_cfg_read_data2(FID_KEY_DATA, offset, (void *)key_data, 3);
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;	
	}
	offset += 3;
	//读取密钥数据
	ret = reader_cfg_read_data2(FID_KEY_DATA, offset, (void *)&key_data->keys, key_data->key_num * sizeof(key_t));
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;
	}
	offset += key_data->key_num * sizeof(key_t);
	//读取MAC
	ret = reader_cfg_read_data2(FID_KEY_DATA, offset, (void *)key_data->cmac, 8);
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;
	}
	return 0;
}

static int reader_cfg_read_key_data2(uint8_t* data, uint16_t* dlen){
	uint16_t offset = 0;
	key_data_t* key_data = (key_data_t*)data;
	//读取版本和密钥数
	int ret = reader_cfg_read_data2(FID_KEY_DATA, offset, data, 3);
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;	
	}
	offset += 3;
	//读取密钥数据
	ret = reader_cfg_read_data2(FID_KEY_DATA, offset, data + offset, key_data->key_num * sizeof(key_t));
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;
	}
	offset += key_data->key_num * sizeof(key_t);
	//读取MAC
	ret = reader_cfg_read_data2(FID_KEY_DATA, offset, data + offset, 8);
	if(ret){
		LOG2_ERR("reader_cfg_read_data fail: %d", ret);
		return ret;
	}
	*dlen = offset + 8;
	return 0;
}

/**
 * @brief 检查配置卡信息的有效性
 * 
 * @param card_info 指向存储卡信息的结构体的指针
 * @return int 返回0表示成功，非0表示失败
 */
static int reader_cfg_check_card_info(cfg_card_t* cfg_card){
    card_info_t* card_info = &cfg_card->info;
	uint8_t kid;
	uint8_t kver;
    // 根据卡的类型获取相应的密钥
    switch (card_info->type) 
    {
    case CARD_T_USER: kid = SAM_KID_KUM; kver = KEY_U_VERSION;	break;
    case CARD_T_CUSTOM: kid = SAM_KID_KCM; kver = KEY_C_VERSION;  break;
    case CARD_T_MANU: kid = SAM_KID_KMM; kver = KEY_M_VERSION; break;
    case CARD_T_INIT: kid = SAM_KID_KFM; kver = KEY_F_VERSION; break;
    default:
        LOG2_ERR("card_type error: %d", card_info->type); // 记录错误日志，卡类型错误
        return -1;
    }
	
    // 检查MAC（消息认证码）是否有效    
    uint8_t div[16] = {0};

	reader_cfg_gen_div(cfg_card->uid, AID_ISSUE, div);
    if(reader_cfg_check_mac_div(kid, kver, div, (uint8_t *)card_info, sizeof(card_info_t))){
        LOG2_ERR("mac check fail"); // 记录错误日志，MAC检查失败
        return -4; // 返回错误码-4    
    }

    return 0; // 返回成功码0
}

/**
 * @brief 读取配置卡信息
 * 
 * @param card_info 指向存储卡信息的结构体的指针
 * @return int 返回0表示成功，非0表示失败
 */
static int reader_read_cfg_card_info(cfg_card_t* cfg_card){
    int ret;
    uint8_t keyNo = 1;
    uint8_t ver = 0;
	card_info_t* card_info = &cfg_card->info;
    //选择应用
    ret = reader_cfg_select_app(AID_ISSUE);
    if(ret){
        return 1;
    }
    //认证密钥
    ret = reader_cfg_auth_card(SAM_KID_KFR0, KEY_NO_KFR0);
    if(ret){
        return 1;
    }
	//读取数据
    ret = reader_cfg_read_data(FID_MANU_INFO, card_info, sizeof(card_info_t));
    if(ret){
        return 3;
    }
    ret = reader_cfg_check_card_info(cfg_card);
    if(ret){
        return 4;
    }
    return 0;
}

static int reader_read_card_data(uint8_t kid_auth, uint8_t kver_auth, uint8_t kid_mac, uint8_t kver_mac, cfg_card_t* cfg_card){
    int ret;

    //选择应用
    ret = reader_cfg_select_app(AID_DATA);
    if(ret){
        return 2;
    }
	//认证密钥    
    uint8_t div[16] = {0};

	reader_cfg_gen_div(cfg_card->uid, AID_DATA, div);
	ret = reader_cfg_auth_card_div(kid_auth, kver_auth, KEY_NO_KUR, div, 16);
    if(ret){
        return 2;
    }

    //读取验证码
    ret = reader_cfg_read_data(FID_USER_INFO, &cfg_card->user, sizeof(card_info_t));
    if(ret){
        return 3;
    }
	uint16_t dlen = 0;
    //读密钥数据
	ret = reader_cfg_read_key_data2((uint8_t*)&cfg_card->key_datas, &dlen);
    if(ret){
        return 5;
    }
    // //校验MAC
	key_data_t* key_data = &cfg_card->key_datas;    
	reader_cfg_gen_div(cfg_card->uid, AID_DATA, div);
	ret = reader_cfg_check_mac_div(kid_mac, kver_mac, div, (uint8_t *)key_data, dlen);
    if(ret){
        return 6;
    }
    return 0;
}

static int reader_read_cfg_card_data(cfg_card_t* cfg_card){
    switch (cfg_card->info.type)
    {
    case CARD_T_USER:	return reader_read_card_data(SAM_KID_KUR, KEY_U_VERSION, SAM_KID_KURM, KEY_U_VERSION, cfg_card);
    case CARD_T_CUSTOM:	return reader_read_card_data(SAM_KID_KCR, KEY_C_VERSION, SAM_KID_KCRM,KEY_C_VERSION,cfg_card);
    case CARD_T_MANU:	return reader_read_card_data(SAM_KID_KMR, KEY_M_VERSION, SAM_KID_KMRM,KEY_M_VERSION,cfg_card);
    case CARD_T_INIT:	return reader_read_card_data(SAM_KID_KFR, KEY_F_VERSION, SAM_KID_KFRM,KEY_F_VERSION,cfg_card);
    default:
        LOG2_ERR("unknow card type: %d", cfg_card->info.type);
        break;
    }

    return -1;
}


static int reader_cfg_kid_to_sam_kid(uint8_t kid, uint8_t sam_kids[2]){
	typedef struct {
		uint8_t kid;
		uint8_t sam_kid[2];
	}kid_to_sam_kid_t;

	static const kid_to_sam_kid_t kid_to_sam_kid[] = {
		{KID_KMR, {SAM_KID_KMR, SAM_KID_KMRM}},
		{KID_KMM, {0, SAM_KID_KMM}},
		{KID_KCR, {SAM_KID_KCR, SAM_KID_KCRM}},
		{KID_KCM, {0, SAM_KID_KCM}},
		{KID_KUR, {SAM_KID_KUR, SAM_KID_KURM}},
		{KID_KUM, {0, SAM_KID_KUM}},
		{KID_APPLE_PRIV, {SAM_KID_APPLE_PRIV, 0}},
		{KID_APPLE_CRED, {SAM_KID_APPLE_CRED, 0}},
		{KID_GOOGLE, {SAM_KID_GOOGLE, SAM_KID_GOOGLE_MAC}},
		{KID_LEAF, {SAM_KID_LEAF, SAM_KID_LEAF_MAC}},
	};

	for(int i = 0; i < sizeof(kid_to_sam_kid)/sizeof(kid_to_sam_kid[0]); i++){
		if(kid_to_sam_kid[i].kid == kid){
			memcpy(sam_kids, kid_to_sam_kid[i].sam_kid, 2);
			return 0;
		}
	}

	return -1;	
}

static int reader_cfg_get_sam_key_type(const key_t* key){
	if(key->id == KID_APPLE_PRIV){
		return SAM_KEY_T_DESFire4;
	}
	switch(key->type){
		case KEY_T_AES128: return SAM_KEY_T_AES_128;
		case KEY_T_AES192: return SAM_KEY_T_AES_192;
		case KEY_T_AES256: return SAM_KEY_T_AES_256;
		case KEY_T_3DES: return SAM_KEY_T_DESFire4;
		case KEY_T_3K3DES: return SAM_KEY_T_3TDEA;
		default: return -1;
	}
}

static int reader_cfg_get_sam_key_keep_iv(const key_t* key){
	if(key->id == KID_APPLE_PRIV){
		return 0;
	}
	return 1;
}

static int reader_cfg_save_key(uint8_t kid, key_t* key){
	int ret;
	uint8_t sam_kid[2];
	ret = reader_cfg_kid_to_sam_kid(kid, sam_kid);
	if(ret){
		LOG2_ERR("unknow key id: %d", kid);
		return -1;
	}

	int sam_key_type = reader_cfg_get_sam_key_type(key);
	if(sam_key_type < 0){
		LOG2_ERR("unknow key type: %d", key->type);
		return -1;
	}

	if(sam_kid[0]){
		uint8_t keep_iv = reader_cfg_get_sam_key_keep_iv(key);
		ret = samav3_load_key(sam_kid[0], key->data, key->ver, SAM_KEY_CLASS_PICC, sam_key_type, keep_iv);
		if(ret){
			LOG2_ERR("samav3_load_key fail: %d", ret);
			return ret;
		}
	}

	if(sam_kid[1]){
		ret = samav3_load_key(sam_kid[1], key->data, key->ver, SAM_KEY_CLASS_OfflineCrypto, sam_key_type, 0);
		if(ret){
			LOG2_ERR("samav3_load_key mac fail: %d", ret);
			return ret;
		}
	}

	return ret;
}

//disable keys
static int reader_cfg_disable_keys(const uint8_t *kids, uint8_t size){
	int ret = 0;
	for(int i = 0; i < size; i++){
		if(kids[i] == 0){
			continue;
		}
		LOG2_WRN("disable key: %02X", kids[i]);
		ret = samav3_disable_key_entry(kids[i]);
		if(ret){
			LOG2_ERR("samav3_disable_key_entry(%02X) fail: %d", kids[i], ret);
			return ret;
		}
	}
	return ret;
}

//保存INIT卡disable keys
static int reader_cfg_save_init_card_disable_keys(cfg_card_t* cfg_card){
	//刷初始化卡，禁用未初始化的密钥。
	int ret = 0;
	uint8_t sam_kids[] = {
		SAM_KID_KMR, SAM_KID_KMRM, SAM_KID_KMM, 
		SAM_KID_KCR, SAM_KID_KCRM, SAM_KID_KCM,
		SAM_KID_KUR, SAM_KID_KURM, SAM_KID_KUM, 
		SAM_KID_APPLE_PRIV, SAM_KID_APPLE_CRED, 
		SAM_KID_GOOGLE, SAM_KID_GOOGLE_MAC,
		SAM_KID_LEAF, SAM_KID_LEAF_MAC
	};
	const uint8_t sam_kids_size = sizeof(sam_kids)/sizeof(sam_kids[0]);
	//保存密钥
	for(int i = 0; i < cfg_card->key_datas.key_num; i++){
		uint8_t sam_kid[2];
		reader_cfg_kid_to_sam_kid(cfg_card->key_datas.keys[i].id, sam_kid);
		//清理匹配的kid
		for(int j = 0; j < sizeof(sam_kids)/sizeof(sam_kids[0]); j++){
			if(sam_kids[j] == 0){
				continue;
			}
			if(sam_kids[j] == sam_kid[0] || sam_kids[j] == sam_kid[1]){
				sam_kids[j] = 0;
			}
		}		
	}

	//清除旧密钥
	return reader_cfg_disable_keys(sam_kids, sam_kids_size);
}

//保存CUSTOM卡,disable keys
static int reader_cfg_save_custom_card_disable_keys(void){
	//刷了客户化卡后，禁用厂商配置卡
	uint8_t sam_kids[] = {
		SAM_KID_KMR, SAM_KID_KMRM, SAM_KID_KMM, 
		SAM_KID_APPLE_PRIV, SAM_KID_APPLE_CRED, 
		SAM_KID_GOOGLE, SAM_KID_GOOGLE_MAC,
		SAM_KID_LEAF, SAM_KID_LEAF_MAC
	};
	const uint8_t sam_kids_size = sizeof(sam_kids)/sizeof(sam_kids[0]);
	return reader_cfg_disable_keys(sam_kids, sam_kids_size);
}
//MANU卡，disable keys
static int reader_cfg_save_manu_card_disable_keys(void){
	//刷了厂商配置卡后，禁用客户化卡
	uint8_t sam_kids[] = {
		SAM_KID_KCR, SAM_KID_KCRM, SAM_KID_KCM
	};
	const uint8_t sam_kids_size = sizeof(sam_kids)/sizeof(sam_kids[0]);
	return reader_cfg_disable_keys(sam_kids, sam_kids_size);
}

//保存配置卡数据
static int reader_cfg_save_card_data(cfg_card_t* cfg_card){
	int ret = 0;
	//保存密钥
	for(int i = 0; i < cfg_card->key_datas.key_num; i++){
		ret = reader_cfg_save_key(cfg_card->key_datas.keys[i].id, &cfg_card->key_datas.keys[i]);
		if(ret){
			return ret;
		}
	}

	switch(cfg_card->info.type){
	case CARD_T_INIT:
		ret = reader_cfg_save_init_card_disable_keys(cfg_card);
		break;
	case CARD_T_CUSTOM:
		ret = reader_cfg_save_custom_card_disable_keys();
		break;
	case CARD_T_MANU:
		ret = reader_cfg_save_manu_card_disable_keys();
		break;
	default :
		break;
	}

	return ret;
}

static int cfg_tag_live;
static SimpleTag_T cfg_tag;
//配置卡定时器
static TimerHandle_t reader_cfg_timer;

//检测tag是否是新tag
static int reader_cfg_is_new_tag(SimpleTag_T* tag){
	if(cfg_tag_live == 0){
		return 1;
	}
	if(tag->ulen != cfg_tag.ulen){
		return 1;	
	}
	if(memcmp(tag->uid, cfg_tag.uid, tag->ulen) != 0){
		return 1;
	}
	return 0;
}

/**
 * @brief 配置wavelynx卡
 * 
 * @return int 返回0表示成功，非0表示失败
 */
int reader_wavelynx_config3(SimpleTag_T* tag){
    cfg_card_t cfg_card;
	if(!reader_cfg_is_new_tag(tag)){
		cfg_tag_live = 20;
		return 0;
	}
	memset(&cfg_card, 0, sizeof(cfg_card));
	memcpy(cfg_card.uid, tag->uid, tag->ulen);
	cfg_card.ulen = tag->ulen;
    int ret = reader_read_cfg_card_info(&cfg_card);
    if(ret){
        return ret;
    }
    reader_pr_cfg_info(&cfg_card.info);
    ret = reader_read_cfg_card_data(&cfg_card);
    if(ret){
        return ret;
    }
    //保存数据
    ret = reader_cfg_save_card_data(&cfg_card);
	if(ret){
		return ret;
	}
	//更新tag
	memcpy(&cfg_tag, tag, sizeof(SimpleTag_T));
	cfg_tag_live = 20;
    return 0;
}


//配置卡定时器回调
static void reader_cfg_tick(TimerHandle_t xTimer){
	if(cfg_tag_live > 0){
		cfg_tag_live--;
		if(cfg_tag_live == 0){
			//配置卡超时
			memset(&cfg_tag, 0, sizeof(cfg_tag));
		}
	}
}

void reader_wavelynx_config_init(void){
	if(!reader_cfg_timer){
		reader_cfg_timer = xTimerCreate("cfg_timer", pdMS_TO_TICKS(100), pdTRUE, NULL, reader_cfg_tick);
	}

	xTimerStart(reader_cfg_timer, portMAX_DELAY);
}

//KFR0密钥
const uint8_t kfr0[16] = {
	0xD2,0x22,0x9A,0xC0,0xF6,0x9F,0xC8,0x4E,
	0x87,0x4F,0x2F,0x88,0xD5,0x52,0x5B,0xA6
};
//KFR密钥
const uint8_t kfr[16] = {
	0xBF,0x84,0xB0,0xCC,0x39,0xD6,0xE1,0x53,
	0xE6,0x76,0x06,0xAF,0x46,0x5C,0x66,0x81
};
//KFM密钥
const uint8_t kfm[16] = {
	0x35,0x55,0x98,0x72,0x35,0xAA,0x4D,0xFB,
	0xF4,0xD8,0x35,0xC0,0x45,0xDF,0xDB,0x98
};


//装载默认配置密钥
int reader_cfg_load_default_key(void){
	int status;
	uint8_t kver = 1;
	uint8_t kclass = SAM_KEY_CLASS_PICC;
	uint8_t ktype = SAM_KEY_T_AES_128;
	uint8_t keep_iv = 1;
	//装载KFR0密钥
	status = samav3_load_key_if_changed(SAM_KID_KFR0, kfr0, kver, kclass, ktype, keep_iv);
	if(status < 0){
		LOG2_ERR("samav3_load_key_if_changed fail: %d", status);
		return status;
	}
	//装载KFR密钥
	status = samav3_load_key_if_changed(SAM_KID_KFR, kfr, kver, kclass, ktype, keep_iv);
	if(status < 0){
		LOG2_ERR("samav3_load_key_if_changed fail: %d", status);
		return status;
	}
	//装载KFM密钥
	kclass = SAM_KEY_CLASS_OfflineCrypto;
	keep_iv = 0;
	status = samav3_load_key_if_changed(SAM_KID_KFM, kfm, kver, kclass, ktype, keep_iv);
	if(status < 0){
		LOG2_ERR("samav3_load_key_if_changed fail: %d", status);
		return status;
	}
	status = samav3_load_key_if_changed(SAM_KID_KFRM, kfr, kver, kclass, ktype, keep_iv);
	if(status < 0){
		LOG2_ERR("samav3_load_key_if_changed fail: %d", status);
		return status;
	}
	return 0;
}

